Skip to content

feat: Add optional FIPS support- #466 - #1743

Merged
tconley1428 merged 8 commits into
temporalio:mainfrom
christiandcucco:feat/fips-support
Aug 13, 2026
Merged

feat: Add optional FIPS support- #466#1743
tconley1428 merged 8 commits into
temporalio:mainfrom
christiandcucco:feat/fips-support

Conversation

@christiandcucco

Copy link
Copy Markdown
Contributor

What was changed

Adds optional, opt-in FIPS 140-3 support for the Rust bridge's TLS stack, ported from temporalio/sdk-ruby #466.

Default behavior is unchanged: normal builds still use the ring rustls provider. When built with TEMPORALIO_FIPS=1 (--no-default-features --features fips), the entire rustls stack — the transitive sdk-core/client
TLS and this crate's own direct tokio-rustls use in client.rs — switches to aws-lc-rs in FIPS mode (linking aws-lc-fips-sys, AWS-LC's FIPS 140-3 module), and ring is eliminated from the build.

Six files:

  • temporalio/bridge/Cargo.toml — new [features] block: default = ["tls-ring"]; tls-ring/tls-aws-lc cascade to sdk-core + client plus this crate's own tokio-rustls provider; fips = ["tls-aws-lc", "dep:aws-lc-rs"].
    Adds optional aws-lc-rs (FIPS feature), and converts the core deps to default-features = false (re-adding their non-TLS defaults) so the provider is no longer pinned to ring.
  • temporalio/bridge/src/lib.rs — exposes FIPS constant at runtime (cfg!(feature = "fips")) and, under fips, installs the aws-lc-rs FIPS provider as the process-wide default at module init.
  • temporalio/bridge/src/client.rs — the custom server-name verifier's provider fallback is now #[cfg]-conditional (aws-lc-rs under fips, ring otherwise); the unconditional ring reference would otherwise fail to
    compile in a FIPS build.
  • pyproject.toml — build-develop-fips / build-wheel-fips poe tasks (the maturin analog of Ruby's extconf.rb env-var hook, since maturin doesn't read env for Cargo features).
  • .github/workflows/ci.yml — new fips-build job: a cargo tree linkage guard (asserts aws-lc-fips-sys present, ring absent) plus a real FIPS wheel build.
  • README.md — new "FIPS Compliance (Experimental)" section under Building.

Why?

Published wheels use ring, which is not FIPS 140-validated. Deployments with a FIPS requirement (e.g. FedRAMP / government) need TLS to run through a validated crypto module. sdk-ruby solved this in #466; this brings the same opt-in build to sdk-python. Because Temporal doesn't publish FIPS binaries, it has to be a build-time feature rather than a runtime switch.

Checklist

  1. Closes issue: No existing issue — happy to open one first if you'd prefer to track it there (there's no FIPS issue today, only the unrelated Flag MD5 as non-security related usage for FIPS compatibility #472).

  2. How was this tested: The default (non-FIPS) path is unchanged and covered by existing CI. The new fips-build job compiles the fips feature set and uses cargo tree to verify aws-lc-fips-sys is linked and ring is absent; the runtime FIPS constant lets you assert a FIPS wheel is loaded (temporalio.bridge.temporal_sdk_bridge.FIPS is True).

  3. Any docs added? Yes — a "FIPS Compliance (Experimental)" section in the README covering the build command, toolchain prerequisites (Go/CMake/Perl/C compiler for aws-lc-fips-sys), and the runtime assert.

@CLAassistant

CLAassistant commented Aug 12, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Add an opt-in FIPS 140-3 build for the Rust bridge's TLS stack, ported
from temporalio/sdk-ruby PR temporalio#466.

Default builds are unchanged (rustls' `ring` provider). Building with
TEMPORALIO_FIPS=1 (--no-default-features --features fips) switches the
entire rustls stack -- the transitive sdk-core/client TLS and this
crate's own tokio-rustls use in client.rs -- to aws-lc-rs in FIPS mode
(linking aws-lc-fips-sys, AWS-LC's FIPS 140-3 module), and eliminates
`ring` from the build.
@christiandcucco
christiandcucco marked this pull request as ready for review August 12, 2026 15:27
@christiandcucco
christiandcucco requested a review from a team as a code owner August 12, 2026 15:27
Comment thread .github/workflows/ci.yml
Comment thread README.md
Comment thread README.md
- ci.yml: run the test suite against the FIPS build (develop build +
  runtime FIPS assert + pytest), not just a link check and wheel build
- README: clarify the experimental note makes no compliance-audit claim
- README: note the default MD5 build-id path can be unavailable on FIPS
  Python builds, and to pass an explicit build_id in that case
@christiandcucco

Copy link
Copy Markdown
Contributor Author

Hi @chris-olszewski @tconley1428, thanks for the fast review! Updated the README for both doc comments (compliance-audit disclaimer + the md5 build-id note for FIPS Python builds), and added a step that runs the test suite against the FIPS build in CI.

@tconley1428

Copy link
Copy Markdown
Contributor

It would appear not to have worked based on your validation, and the cargo.lock is out of date.

`cargo tree -i <pkg>` exits 0 whether or not the package is in the
dependency graph -- when absent it prints "nothing to print" to stderr.
The guard keyed off the exit code, so the ring-absent check failed
unconditionally (and the aws-lc-fips-sys-present check would falsely
pass if that crate ever went missing). Judge linkage on captured
stdout instead, matching sdk-ruby PR temporalio#466's fips_tree guard.
Comment thread .github/workflows/ci.yml Outdated
@tconley1428 tconley1428 self-assigned this Aug 13, 2026
The FIPS Cargo.toml declares aws-lc-rs as an optional dependency, which the committed Cargo.lock did not record. check-protos runs a develop build that regenerates the lock and then fails on the resulting diff. Update Cargo.lock so it already carries aws-lc-fips-sys/aws-lc-rs/aws-lc-sys and the quinn entries the resolver pulls in.

Also rename the linkage-guard helper (fips_tree -> links_in_fips_build) and expand its comment to explain that `cargo tree -i` inverts the graph and that PRESENT/ABSENT is judged on captured output, not exit code.
@tconley1428
tconley1428 merged commit 680a6b4 into temporalio:main Aug 13, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants